﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using JY.Common.Extensions;

namespace JY.Common.Helpers
{
    /// <summary>
    /// 共享内存帮助类
    /// </summary>
    public static class SharedMemoryHelper
    {
        #region # 属性&变量
        #region 默认共享内存名称——string DefualtMapName
        /// <summary>
        /// 默认共享内存名称
        /// </summary>
        public const string DefualtMapName = "JYSharedMemory";
        #endregion 
        #region 共享内存状态名称——string SharedMemoryStatusMapName
        /// <summary>
        /// 共享内存状态名称
        /// </summary>
        public const string SharedMemoryStatusMapName = "JYSharedMemoryStatus";
        #endregion 
        /// <summary>
        /// 数据接收事件
        /// </summary>
        public static event EventHandler<string> DataReceived;
        /// <summary>
        /// 同步锁
        /// </summary>
        private static readonly object Locker = new object();

        private static bool IsBusy { get; set; }

        private static Guid? _clientId;
        #endregion

        #region # 方法
        #region # 写入数据到共享内存——void WriteDataToSharedMemory(string writeData,string mapName = DefualtMapName, long capacity = 10485760)
        /// <summary>
        /// 写入数据到共享内存
        /// </summary>
        /// <param name="writeData">数据</param>
        /// <param name="mapName">共享内存名称</param>
        /// <param name="capacity">共享内存大小（字节）</param>
        public static void WriteDataToSharedMemory(string writeData, string mapName = DefualtMapName, long capacity = 10485760)
        {
            SharedMemoryHelper.IsBusy = true;
            lock (Locker)
            {
                var memoryMappedFile = MemoryMappedFile.CreateOrOpen(mapName, capacity, MemoryMappedFileAccess.ReadWrite);
                {
                    using (var accessor = memoryMappedFile.CreateViewStream(0, capacity))
                    {
                        BinaryWriter binaryWriter = new BinaryWriter(accessor);
                        binaryWriter.Write(writeData);
                    }
                }
            }
            SharedMemoryHelper.IsBusy = false;
        }
        #endregion

        #region # 读取共享内存数据——string ReadDataFromSharedMemory(string mapName = DefualtMapName, long capacity = 10485760)
        /// <summary>
        /// 读取共享内存数据
        /// </summary>
        /// <param name="mapName">共享内存名称</param>
        /// <param name="capacity">共享内存大小（字节）</param>
        public static string ReadDataFromSharedMemory(string mapName = DefualtMapName, long capacity = 10485760)
        {
            return ReadDataFromSharedMemoryPair(mapName, capacity).Key;
        }
        #endregion
        #region # 读取共享内存数据——string ReadDataFromSharedMemoryPair(string mapName = DefualtMapName, long capacity = 10485760)
        /// <summary>
        /// 读取共享内存数据
        /// </summary>
        /// <param name="mapName">共享内存名称</param>
        /// <param name="capacity">共享内存大小（字节）</param>
        private static KeyValuePair<string, string> ReadDataFromSharedMemoryPair(string mapName = DefualtMapName, long capacity = 10485760)
        {
            SharedMemoryHelper.IsBusy = true;
            KeyValuePair<string, string> result = new KeyValuePair<string, string>();
            string sharedMemoryData = "";
            lock (Locker)
            {
                var memoryMappedFile = MemoryMappedFile.CreateOrOpen(mapName, capacity, MemoryMappedFileAccess.ReadWrite);
                {
                    using (var accessor = memoryMappedFile.CreateViewStream(0, capacity))
                    {
                        BinaryReader binaryReader = new BinaryReader(accessor);
                        sharedMemoryData = binaryReader.ReadString();
                    }
                    if (!string.IsNullOrWhiteSpace(sharedMemoryData))
                    {
                        var splitSharedMemoryData = sharedMemoryData.Split(new string[1] { "[分隔符]" }, StringSplitOptions.None);
                        result = new KeyValuePair<string, string>(splitSharedMemoryData[0], splitSharedMemoryData.Length <= 1 ? "" : splitSharedMemoryData[1]);

                        if (splitSharedMemoryData.Length <= 1 || (!splitSharedMemoryData[1].Contains(_clientId.ToString())))
                        {
                            using (var accessor = memoryMappedFile.CreateViewStream(0, capacity))
                            {
                                BinaryWriter binaryWriter = new BinaryWriter(accessor);
                                string key = splitSharedMemoryData[0];
                                string value = splitSharedMemoryData.Length <= 1 ? "[" + _clientId.ToString() + "]" : (splitSharedMemoryData[1] + "[" + _clientId.ToString() + "]");
                                var newSharedMemoryData = key + "[分隔符]" + value;
                                binaryWriter.Write(newSharedMemoryData);
                            }
                        }
                    }
                }
            }

            SharedMemoryHelper.IsBusy = false;
            return result;
        }
        #endregion

        #region # 初始化自动接收数据——void InitAutoReceive(string mapName = DefualtMapName, long capacity = 10485760)
        /// <summary>
        /// 初始化自动接收数据
        /// </summary>
        /// <param name="clientId">客户端Id</param>
        /// <param name="mapName">共享内存名称</param>
        /// <param name="capacity">共享内存大小（字节）</param>
        public static void InitAutoReceive(Guid clientId, string mapName = DefualtMapName, long capacity = 10485760)
        {
            _clientId = clientId;
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerSupportsCancellation = true;
            worker.DoWork += (s, e) =>
            {
                while (!e.Cancel)
                {
                    if (worker.CancellationPending)
                    {
                        e.Cancel = true;
                        continue;
                    }
                    if (SharedMemoryHelper.IsBusy == true) continue;
                    Thread.Sleep(100);
                    var sharedMemoryData = ReadDataFromSharedMemoryPair(mapName, capacity);
                    if (sharedMemoryData.Value != null && !sharedMemoryData.Value.Contains(clientId.ToString()))
                    {
                        try
                        {
                            DataReceived?.Invoke(s, sharedMemoryData.Key);
                        }
                        catch (Exception ex)
                        {

                        }
                    }
                    continue;
                }
            };
            worker.RunWorkerAsync();
        } 
        #endregion

        #endregion
    }
}
